/*******************************************************************************
 * Copyright (c) 2012, 2025 AIT, fortiss GmbH, Davor Cihlar
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Filip Andren, Alois Zoitl - initial API and implementation and/or initial documentation
 *   Davor Cihlar - multiple FBs sharing a single Modbus connection
 *******************************************************************************/
#include "modbusconnection.h"
#include "modbuslayer.h"

namespace forte::com_infra::modbus {

  CModbusConnection::CModbusConnection(CModbusHandler *pa_modbusHandler) :
      mModbusConn(nullptr),
      mModbusHandler(pa_modbusHandler),
      mConnected(false),
      mIPAddress(nullptr),
      mPort(0),
      mDevice{0},
      mBaud(0),
      mParity(0),
      mDataBit(0),
      mStopBit(0),
      mFlowControl(eFlowNone),
      mResponseTimeout(0),
      mByteTimeout(0) {
  }

  CModbusConnection::~CModbusConnection() {
    modbus_free(mModbusConn);
  }

  int CModbusConnection::connect() {
    if (mIPAddress != nullptr) {
      mModbusConn = modbus_new_tcp(mIPAddress, mPort);
    } else {
      mModbusConn = modbus_new_rtu(mDevice, mBaud, mParity, mDataBit, mStopBit);
    }

#if 0
  if(mResponseTimeout > 0){
    timeval responseTimeout;
    responseTimeout.tv_sec = mResponseTimeout / 1000;
    responseTimeout.tv_usec = (mResponseTimeout % 1000)*1000;
    modbus_set_response_timeout(mModbusConn, &responseTimeout);
  }
  if(mByteTimeout > 0){
    timeval byteTimeout;
    byteTimeout.tv_sec = mByteTimeout / 1000;
    byteTimeout.tv_usec = (mByteTimeout % 1000)*1000;
    modbus_set_byte_timeout(mModbusConn, &byteTimeout);
  }
#endif

    return 0;
  }

  void CModbusConnection::disconnect() {
  }

  void CModbusConnection::setIPAddress(const char *paIPAddress) {
    mIPAddress = paIPAddress;
  }

  void CModbusConnection::setPort(unsigned int paPort) {
    mPort = paPort;
  }

  void CModbusConnection::setDevice(const char *paDevice) {
    strcpy(mDevice, paDevice);
  }

  void CModbusConnection::setBaud(int paBaud) {
    mBaud = paBaud;
  }

  void CModbusConnection::setParity(char paParity) {
    mParity = paParity;
  }

  void CModbusConnection::setDataBit(int paDataBit) {
    mDataBit = paDataBit;
  }

  void CModbusConnection::setStopBit(int paStopBit) {
    mStopBit = paStopBit;
  }

  void CModbusConnection::setFlowControl(EModbusFlowControl paFlowControl) {
    mFlowControl = paFlowControl;
  }

  void CModbusConnection::setResponseTimeout(unsigned int paResponseTimeout) {
    mResponseTimeout = paResponseTimeout;
  }

  void CModbusConnection::setByteTimeout(unsigned int paByteTimeout) {
    mByteTimeout = paByteTimeout;
  }

  int CModbusConnection::writeData(CModbusIOBlock *paIOBlock, const void *paData, unsigned int paDataSize) {
    unsigned int dataIndex = 0;
    const CModbusIOBlock::TModbusRangeList &lSends = paIOBlock->getSends();
    for (auto &it : lSends) {
      const unsigned int nextDataIndex = dataIndex + it.mNrAddresses * CModbusIOBlock::getRegisterSize(it.mFunction);
      if (nextDataIndex > paDataSize) {
        const unsigned int maxNrAddresses = (paDataSize - dataIndex) / CModbusIOBlock::getRegisterSize(it.mFunction);
        DEVLOG_WARNING("Modbus writing %u instead of %u registers from address %u\n", maxNrAddresses, it.mNrAddresses,
                       it.mStartAddress);
        writeDataRange(it.mFunction, it.mStartAddress, maxNrAddresses, (const uint8_t *) paData + dataIndex);
        break;
      }
      writeDataRange(it.mFunction, it.mStartAddress, it.mNrAddresses, (const uint8_t *) paData + dataIndex);
      dataIndex = nextDataIndex;
    }
    return (int) dataIndex;
  }

} // namespace forte::com_infra::modbus
